#include "bsp_iic.h"
#include "main.h"

#define IIC_DELAY_24Cxx 	HAL_Delay(15)

#define RECORD_24CXX_ADDR 	0xA0

uint8_t IIC_REGADDR_MODE;	//	1 is 16 bit adders | 0 is 8 bit adders
uint8_t IIC_REGPAGE_SIZE;	//32 or 64

	
#define TIMEOUT ((uint32_t)0xF0000)
#define LONG_TIMEOUT ((uint32_t)0xF0000)

#define IIC_SDA_H	HAL_GPIO_WritePin(GPIOB, SDA_Pin, GPIO_PIN_SET)
#define IIC_SDA_L	HAL_GPIO_WritePin(GPIOB, SDA_Pin, GPIO_PIN_RESET)
#define IIC_SDA_R	HAL_GPIO_ReadPin(GPIOB, SDA_Pin)

#define IIC_SCL_H	HAL_GPIO_WritePin(GPIOB, SCL_Pin, GPIO_PIN_SET)
#define IIC_SCL_L	HAL_GPIO_WritePin(GPIOB, SCL_Pin, GPIO_PIN_RESET)
#define IIC_SCL_R	HAL_GPIO_ReadPin(GPIOB, SCL_Pin)

uint32_t iic_timeout;

static void delay_us(uint16_t us)
{
	int i,j;
	
	for(i=0;i<us;i++)
	{
		for(j=0;j<128;j++);
	}
}

#define IIC_DELAY		{delay_us(10);}	

////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////
#define IIC_ERROR return 0xff

void iic_init(void)
{
    GPIO_InitTypeDef GPIO_InitStruct = {0};
    
    HAL_GPIO_WritePin(GPIOB, SCL_Pin|SDA_Pin, GPIO_PIN_SET);
    
    GPIO_InitStruct.Pin = SCL_Pin|SDA_Pin;
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

	IIC_REGADDR_MODE = 1;
	IIC_REGPAGE_SIZE = 64;
}

void iic_gene_start(void)
{
	if(!IIC_SDA_R)
	{
		if(IIC_SCL_R)
		{
			IIC_SCL_L;IIC_DELAY;
		}
		IIC_SDA_H;IIC_DELAY;
	}
	if(!IIC_SCL_R)
	{
		IIC_SCL_H;IIC_DELAY;
	}
	IIC_SDA_L;IIC_DELAY;
}

void iic_gene_stop(void)
{
	if(IIC_SDA_R)
	{
		if(IIC_SCL_R)
		{
			IIC_SCL_L;IIC_DELAY;
		}
		IIC_SDA_L;IIC_DELAY;
	}
	if(!IIC_SCL_R)
	{
		IIC_SCL_H;IIC_DELAY;
	}
	IIC_SDA_H;IIC_DELAY;
}

void iic_gene_restart(void)
{
	IIC_SCL_L;IIC_DELAY;
	IIC_SDA_H;IIC_DELAY;
	IIC_SCL_H;IIC_DELAY;
	IIC_SDA_L;IIC_DELAY;
}

void iic_gene_idle(void)
{
	IIC_SDA_H;IIC_SCL_H;IIC_DELAY;
}

uint8_t iic_send8data(uint8_t data)
{
	uint8_t tmp;
	IIC_DELAY;
	for(tmp=7;tmp<8;tmp--)
	{
		IIC_SCL_L;
		IIC_DELAY;
		if(data & 0x80)
		{
			IIC_SDA_H;
		}
		else
		{
			IIC_SDA_L;
		}
		IIC_DELAY;
		IIC_SCL_H;
		IIC_DELAY;
		data = data << 1;
	}
	IIC_SCL_L;
	IIC_DELAY;
	return 0;
}

uint8_t iic_read8data(uint8_t * data)
{
	uint8_t tmp;
	*data = 0;
	IIC_SCL_L;
	IIC_DELAY;
	IIC_SDA_H;
	// IIC_DELAY;
	for(tmp=7;tmp<8;tmp--)
	{
		IIC_SCL_L;
		IIC_DELAY;
		*data = *data << 1;
		if(IIC_SDA_R)
		{
			*data |= 0x01;
		}
		else
		{
			*data &= 0xFE;
		}
		// IIC_DELAY;
		IIC_SCL_H;
		IIC_DELAY;
	}
	return 0;
}

uint8_t iic_check_busy(void)
{
	uint8_t tmp;
	if(!(IIC_SDA_R && IIC_SCL_R))
	for(tmp=5;tmp<6;tmp--)
	{
		IIC_DELAY;
		if(!(IIC_SDA_R && IIC_SCL_R))
			return 1;
	}
	IIC_DELAY;
	return 0;
}

uint8_t iic_sendack(void)
{
	IIC_SCL_L;
	IIC_DELAY;
	IIC_SDA_L;
	IIC_DELAY;
	IIC_SCL_H;
	IIC_DELAY;
	IIC_SCL_L;
	IIC_DELAY;
	return 0;
}

uint8_t iic_sendnak(void)
{
	IIC_SCL_L;
	IIC_DELAY;
	IIC_SDA_H;
	IIC_DELAY;
	IIC_SCL_H;
	IIC_DELAY;
	IIC_SCL_L;
	IIC_DELAY;
	return 0;
}

uint8_t iic_checkack(void)
{
	uint8_t tmp;
	IIC_SCL_L;
	IIC_DELAY;
	IIC_SDA_H;
	IIC_DELAY;
	tmp = IIC_SDA_R;
	// IIC_DELAY;
	IIC_SCL_H;
	IIC_DELAY;
	IIC_SCL_L;
	IIC_DELAY;
	return tmp;
}

uint8_t iicsingle_write(uint8_t slaveaddr,uint16_t regaddr,uint8_t data)
{
	if(iic_check_busy())
		return 1;

	iic_gene_start();

	iic_send8data(slaveaddr & 0xfe);
	if(iic_checkack())	return 2;

	if(IIC_REGADDR_MODE)
	{
		iic_send8data((uint8_t)(regaddr>>8));
		if(iic_checkack())	return 3;
	}
	iic_send8data((uint8_t)regaddr);
	if(iic_checkack())	return 4;
	iic_send8data((uint8_t)data);
	if(iic_checkack())	return 5;
	iic_gene_stop();
	// delay_ms(1);
	return 0;
}

uint8_t iicsingle_read(uint8_t slaveaddr,uint16_t regaddr,uint8_t*data)
{
	if(iic_check_busy())
		return 1;

	iic_gene_start();

	iic_send8data(slaveaddr&0xfe);
	if(iic_checkack())	return 2;

	if(IIC_REGADDR_MODE)
	{
		iic_send8data((uint8_t)(regaddr>>8));
		if(iic_checkack())	return 3;
	}
	iic_send8data((uint8_t)regaddr);
	if(iic_checkack())	return 4;

	iic_gene_start();
	iic_send8data(slaveaddr|0x01);
	if(iic_checkack())	return 5;

	iic_read8data(data);
	iic_sendack();
	iic_gene_stop();
	// delay_ms(1);
	return 0;
}
/////////////////////////////////////////////////////////////////////////
uint8_t iicmultiply_write(uint8_t slaveaddr,uint16_t regaddr,uint8_t * data,uint16_t number)
{
	if(iic_check_busy()){
		return 1;
	}

	iic_gene_start();

	iic_send8data(slaveaddr&0xfe);
	if(iic_checkack()){
		iic_gene_stop();
		return 2;
	}

	if(IIC_REGADDR_MODE)
	{
		iic_send8data((uint8_t)(regaddr>>8));
		if(iic_checkack()){
			iic_gene_stop();
			return 3;
		}	
	}
	iic_send8data((uint8_t)regaddr);
	if(iic_checkack()){
		iic_gene_stop();
		return 4;
	}
	for(;number>0;number--)
	{
		iic_send8data(*data);
		if(iic_checkack()){
			iic_gene_stop();
			return 0x15;
		}
		data++;
	}
	iic_gene_stop();
	// delay_ms(1);
	return 0;
}

uint8_t iicmultiply_read(uint8_t slaveaddr,uint16_t regaddr,uint8_t * data,uint16_t number)
{
	if(iic_check_busy()){
		return 1;
	}

	iic_gene_start();

	iic_send8data(slaveaddr&0xfe);
	if(iic_checkack()){
		iic_gene_stop();
		return 2;
	}

	if(IIC_REGADDR_MODE)
	{
		iic_send8data((uint8_t)(regaddr>>8));
		if(iic_checkack()){
			iic_gene_stop();
			return 3;
		}
	}
	iic_send8data((uint8_t)regaddr);
	if(iic_checkack()){
		iic_gene_stop();
		return 4;
	}

	iic_gene_start();
	iic_send8data(slaveaddr|0x01);
	if(iic_checkack()){
		iic_gene_stop();
		return 5;
	}

	for(;number>0;number--)
	{
		iic_read8data(data);
		if(number == 1)
		{
			iic_sendnak();
		}
		else
		{
			iic_sendack();
		}
		data++;
	}
	iic_gene_stop();
	// delay_ms(5);
	return 0;
}

void iic_24cxx_write(uint8_t slaveaddr,uint16_t regaddr,uint8_t * data,uint16_t number)
{
	uint16_t tmp_addr_end;
	uint16_t tmp_addr_start;
	uint8_t tmp_count;
    uint8_t res;

	tmp_addr_start = regaddr;
	tmp_addr_end = (tmp_addr_start & (0x10000-IIC_REGPAGE_SIZE));
	//IIC_DELAY_24Cxx;
	while(number)
	{
		tmp_addr_end += IIC_REGPAGE_SIZE;
		if(tmp_addr_start + number >= tmp_addr_end)
		{
			tmp_count = tmp_addr_end - tmp_addr_start;
		}
		else
		{
			tmp_count = number;
		}

		res = iicmultiply_write(slaveaddr,tmp_addr_start,data,tmp_count);        
        if(res != 0)
        {
        
        }
				
		data += tmp_count;
		tmp_addr_start = tmp_addr_end;
		number -= tmp_count;
		IIC_DELAY_24Cxx;
	}
}



void iic_24cxx_read(uint8_t slaveaddr,uint16_t regaddr,uint8_t * data,uint16_t number)
{
	uint16_t tmp_addr_end;
	uint16_t tmp_addr_start;
	uint8_t tmp_count;
    uint8_t res;

	tmp_addr_start = regaddr;
	tmp_addr_end = (tmp_addr_start & (0x10000-IIC_REGPAGE_SIZE));
	//IIC_DELAY_24Cxx;
	while(number)
	{
		tmp_addr_end += IIC_REGPAGE_SIZE;
		if(tmp_addr_start + number >= tmp_addr_end)
		{
			tmp_count = tmp_addr_end - tmp_addr_start;
		}
		else
		{
			tmp_count = number;
		}

		res = iicmultiply_read(slaveaddr,tmp_addr_start,data,tmp_count);
        if(res != 0)
        {
        
        }
		
		data += tmp_count;
		tmp_addr_start = tmp_addr_end;
		number -= tmp_count;
		IIC_DELAY_24Cxx;
	}
}


/////////////////////////////////////////////////////////////////////////////////////////////////////////

void eeprom_write(uint16_t regaddr,uint8_t * data,uint16_t number)
{
	iic_24cxx_write(RECORD_24CXX_ADDR,regaddr,data,number);
}


void eeprom_read(uint16_t regaddr,uint8_t * data,uint16_t number)
{
	iic_24cxx_read(RECORD_24CXX_ADDR,regaddr,data,number);
}
